//
// Created by 86186 on 2021/12/7.
//

#include "OpenSlPlayer.h"

class ImplData {
public:
    SLObjectItf engineObject = NULL;
    SLEngineItf engineEngine = NULL;

    SLObjectItf outputMixObj = NULL;
    SLEnvironmentalReverbItf outputMixEnvironmentalReverb = NULL;

    SLObjectItf playerObject = NULL;
    SLPlayItf playerPlay = NULL;

    SLAndroidSimpleBufferQueueItf androidSimpleBufferQueue = NULL;

    AVPacketQueue *avPacketQueue = NULL;
    DecodeResource *resource = NULL;

    uint8_t *buffer = (uint8_t *) av_malloc(44100 * 2 * (16 / 8));

    ~ImplData() {
        if (engineObject != NULL) {

        }
    }
};

void pcmBufferCallBack(SLAndroidSimpleBufferQueueItf androidSimpleBufferQueue, void *context) {
    OpenSlPlayer *openSlPlayer = (OpenSlPlayer *) context;
//    (*openSlPlayer->data->androidSimpleBufferQueue)->Enqueue(
//            openSlPlayer->data->androidSimpleBufferQueue, openSlPlayer->data->buffer,
//            openSlPlayer->data->dataSize);

    if (openSlPlayer->data->avPacketQueue == nullptr) {
        if (LOG_DEBUG) LOGE("当前队列为null")
        return;
    }
    auto curAvPacket = openSlPlayer->data->avPacketQueue->pop();
    if (LOG_DEBUG) LOGD("出队！")
    int ret = avcodec_send_packet(openSlPlayer->data->resource->avCodecContext,
                                  curAvPacket); //将AVPacket放入解码器
    if (ret == 0) {
        AVFrame *avFrame = av_frame_alloc();
        ret = avcodec_receive_frame(openSlPlayer->data->resource->avCodecContext,
                                    avFrame); //Return decoded output data from a decoder
        if (ret == 0) {
            if (avFrame->channels > 0 && avFrame->channel_layout == 0) {
                avFrame->channel_layout = av_get_default_channel_layout(avFrame->channels);
            } else if (avFrame->channels == 0 && avFrame->channel_layout > 0) {
                avFrame->channels = av_get_channel_layout_nb_channels(
                        avFrame->channel_layout);
            }
            SwrContext *swrContext = swr_alloc_set_opts(NULL, AV_CH_LAYOUT_STEREO,
                                                        AV_SAMPLE_FMT_S16,
                                                        avFrame->sample_rate,
                                                        avFrame->channel_layout,
                                                        (AVSampleFormat) avFrame->format,
                                                        avFrame->sample_rate, NULL, NULL);
            ret = swr_init(swrContext);
            if (ret >= 0) {
                int nb = swr_convert(swrContext, &openSlPlayer->data->buffer, avFrame->nb_samples,
                                     (const uint8_t **) avFrame->data,
                                     avFrame->nb_samples); //@return number of samples output per channel, negative value on error
                int outChannels = av_get_channel_layout_nb_channels(AV_CH_LAYOUT_STEREO);
                int dataSize =
                        nb * outChannels * av_get_bytes_per_sample(AV_SAMPLE_FMT_S16);
                if (LOG_DEBUG) LOGD("解码完成！！！")
                (*openSlPlayer->data->androidSimpleBufferQueue)->Enqueue(
                        openSlPlayer->data->androidSimpleBufferQueue, openSlPlayer->data->buffer,
                        dataSize);
            }
            if (swrContext != NULL) {
                swr_free(&swrContext);
            }
        }
        av_frame_free(&avFrame);
        av_free(avFrame);
    }

    av_packet_free(&curAvPacket);
    av_free(curAvPacket);
    curAvPacket = NULL;
}

void OpenSlPlayer::play() {
    //设置播放状态
    (*data->playerPlay)->SetPlayState(data->playerPlay, SL_PLAYSTATE_PLAYING);
}

void OpenSlPlayer::pause() {
    (*data->playerPlay)->SetPlayState(data->playerPlay, SL_PLAYSTATE_PAUSED);
}

void OpenSlPlayer::stop() {
    (*data->playerPlay)->SetPlayState(data->playerPlay, SL_PLAYSTATE_STOPPED);
}

OpenSlPlayer::OpenSlPlayer(AVPacketQueue *avPacketQueue, DecodeResource *resource) {
    this->data = new ImplData();
    this->data->avPacketQueue = avPacketQueue;
    this->data->resource = resource;
    ImplData *data = this->data;
    //创建接口对象
    slCreateEngine(&data->engineObject, 0, 0, 0, 0, 0);
    (*data->engineObject)->Realize(data->engineObject, SL_BOOLEAN_FALSE);
    (*data->engineObject)->GetInterface(data->engineObject, SL_IID_ENGINE, &data->engineEngine);

    //设置与创建混音器
    const SLInterfaceID mids[1] = {SL_IID_ENVIRONMENTALREVERB};
    const SLboolean mreq[1] = {SL_BOOLEAN_FALSE};
    (*data->engineEngine)->CreateOutputMix(data->engineEngine, &data->outputMixObj, 1, mids, mreq);
    (*data->outputMixObj)->Realize(data->outputMixObj, SL_BOOLEAN_FALSE);
    (*data->outputMixObj)->GetInterface(data->outputMixObj, SL_IID_ENVIRONMENTALREVERB,
                                        &data->outputMixEnvironmentalReverb);
    SLEnvironmentalReverbSettings environmentalReverbSettings = SL_I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR;
    (*data->outputMixEnvironmentalReverb)->SetEnvironmentalReverbProperties(
            data->outputMixEnvironmentalReverb, &environmentalReverbSettings);

    //创建播放器（录音器）
    SLDataLocator_AndroidSimpleBufferQueue androidBufferQueue = {
            SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};
    SLDataFormat_PCM pcmFormat = {
            SL_DATAFORMAT_PCM,
            2,
            SL_SAMPLINGRATE_44_1,
            SL_PCMSAMPLEFORMAT_FIXED_16,
            SL_PCMSAMPLEFORMAT_FIXED_16,
            SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT,
            SL_BYTEORDER_LITTLEENDIAN //小端
    };
    SLDataSource dataSource = {&androidBufferQueue, &pcmFormat};
    SLDataLocator_OutputMix outputMix = {SL_DATALOCATOR_OUTPUTMIX, data->outputMixObj};
    SLDataSink dataSink = {&outputMix, NULL};
    const SLInterfaceID ids[1] = {SL_IID_BUFFERQUEUE};
    const SLboolean req[1] = {SL_BOOLEAN_TRUE};

    (*data->engineEngine)->CreateAudioPlayer(data->engineEngine, &data->playerObject, &dataSource,
                                             &dataSink, 1, ids, req);
    (*data->playerObject)->Realize(data->playerObject, SL_BOOLEAN_FALSE);
    (*data->playerObject)->GetInterface(data->playerObject, SL_IID_PLAY, &data->playerPlay);

    //设置缓冲队列和回调函数
    (*data->playerObject)->GetInterface(data->playerObject, SL_IID_BUFFERQUEUE,
                                        &data->androidSimpleBufferQueue);
    (*data->androidSimpleBufferQueue)->RegisterCallback(data->androidSimpleBufferQueue,
                                                        pcmBufferCallBack, this);

    //启动回调函数
    pcmBufferCallBack(data->androidSimpleBufferQueue, this);
}

OpenSlPlayer::~OpenSlPlayer() {
    if (this->data != nullptr) delete this->data;
}




